// ThreadingTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <conio.h>
#include <windows.h>
#include <time.h>

HANDLE joinSem;
static HANDLE semaphore0;
static HANDLE semaphore1;

static HANDLE created0_semaphore;
static HANDLE created1_semaphore;

int thread0_count = -1;
int thread1_count = -1;

volatile int count;

static unsigned long threadFn(void* ctx)
{
	int l = (int)ctx;
	HANDLE my_semaphore;
	HANDLE other_semaphore;
	HANDLE created;

	printf("thread %d started\n", l);
	if(l==0)
	{
		thread0_count = l;
		my_semaphore = semaphore0;
		other_semaphore = semaphore1;   
		created = created0_semaphore;  
	}
	else
	{
		thread1_count = l;
		my_semaphore = semaphore1;
		other_semaphore = semaphore0;   
		created = created1_semaphore;  
	}

	::ReleaseSemaphore(created, 1, NULL);

	while (1)
	{
		::WaitForSingleObject(my_semaphore, INFINITE);
		count--;
		::ReleaseSemaphore(other_semaphore, 1, NULL);
		if(count <= 0)
			break;
	}
	printf("finished %d\n",l);
	//	::ReleaseSemaphore(joinSem, 1, NULL);
	return 0;
}



int _tmain(int argc, _TCHAR* argv[])
{
	int count_start;
	time_t start;
	time_t end;

	if(argc < 2){
		printf("usage: test [count] [setup]\n");
		exit(0);
	}
	
	count_start = count = _ttoi(argv[1]);
	printf("Start. Count = %d\n", count_start);

	semaphore0 = ::CreateSemaphore(NULL, 0, 1, NULL);
	semaphore1 = ::CreateSemaphore(NULL, 0, 1, NULL);

	created0_semaphore = ::CreateSemaphore(NULL, 0, 1, NULL);
	created1_semaphore = ::CreateSemaphore(NULL, 0, 1, NULL);

	//	joinSem = ::CreateSemaphore(NULL, 0, 2, NULL);


	HANDLE tFirst = ::CreateThread(NULL, 2048, (LPTHREAD_START_ROUTINE)threadFn, (void*)0, 0, NULL);
	HANDLE tSecond = ::CreateThread(NULL, 2048,(LPTHREAD_START_ROUTINE)threadFn, (void*)1, 0, NULL);

	::WaitForSingleObject(created0_semaphore, INFINITE);
	::WaitForSingleObject(created1_semaphore, INFINITE);
	printf("threads ready to execute\n");

	if(argc == 3)
	{
		printf("Scheduler setup\n");
		bool r;
		r = SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
		printf("%d\n", r);
		r = SetThreadPriority(tFirst, THREAD_PRIORITY_TIME_CRITICAL);
		printf("%d\n", r);
		r = SetThreadPriority(tSecond, THREAD_PRIORITY_TIME_CRITICAL);
		printf("%d\n", r);
	}

	printf("start\n");
	start = time(0);

	::ReleaseSemaphore(semaphore0, 1, NULL);

	::WaitForSingleObject(tFirst, INFINITE);
	::WaitForSingleObject(tSecond, INFINITE);

	end = time(0);

	float f = count_start/(end-start);
    printf("%d context switches in %d seconds.\n",count_start, (end-start));
	printf("%f switches/sec\n", f);

	::CloseHandle(semaphore0);
	::CloseHandle(semaphore1);
	::CloseHandle(created0_semaphore);
	::CloseHandle(created1_semaphore);

	::CloseHandle(tFirst);
	::CloseHandle(tSecond);
}
